/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

//
// Created by WangYunlai on 2023/06/28.
//

#include <sstream>
#include "sql/parser/value.h"
#include "storage/field/field.h"
#include "common/log/log.h"
#include "common/lang/comparator.h"
#include "common/lang/string.h"

#include<string>
#include <iostream>

const char *ATTR_TYPE_NAME[] = {"undefined", "chars", "ints", "floats","dates", "booleans"};  //这里需要修改   类型数组

const char *attr_type_to_string(AttrType type)//枚举转字符串  （这个函数和下个函数共同完成这项任务）
{
  if (type >= UNDEFINED && type <= DATES) {
    return ATTR_TYPE_NAME[type];
  }
  return "unknown";                         //相当于不在枚举范围内
}
AttrType attr_type_from_string(const char *s){   //将字符串识别为枚举
  for (unsigned int i = 0; i < sizeof(ATTR_TYPE_NAME) / sizeof(ATTR_TYPE_NAME[0]); i++) {
    if (0 == strcmp(ATTR_TYPE_NAME[i], s)) {    //将这个字符串与我们类型数组进行比较
      return (AttrType)i;                           
    }
  }
  return UNDEFINED;
}

Value::Value(int val)//value函数定义
{
  set_int(val);
}

Value::Value(float val)
{
  set_float(val);
}

Value::Value(bool val)
{
  set_boolean(val);
}

Value::Value(const char *s, int len /*= 0*/)
{
  set_string(s, len);
}
Value::Value(const char *date, int len ,int flag){//date
  int  intDate = 0;    
  bool is_leap_year = false;
  int year = 0;
  int month = 0;
  int day = 0;
  bool big_month = false;
  int jud = sscanf(date, "%d-%d-%d", &year,& month,& day);
  if(year > 9999){
    //throw "year inappropriate!!!";
    return ;
  }
  if(jud != 3)
   // throw "Date_Form illegal!!!";
 
  return  ;
   if(month > 12 || month < 0){

  return ;
  }
  if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
    is_leap_year = true;
  if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) 
    big_month = true;
   if(big_month && (day < 1 || day > 31)){
        //throw "day illegal";
  return;
      }
      if(!big_month && month != 2 &&  (day < 1 || day > 30))
       //throw "day illegal";
        return ; 
      if(month == 2  && (day < 1 || day > 28)){
          if(is_leap_year){
            intDate = day + month * 100 + year * 10000; 
            set_date(intDate);
            return;
          }
          //throw "day illegal";
          return ;
      }
 
  intDate = day + month * 100 + year * 10000; 

  set_date(intDate);
}
void Value::set_data(char *data, int length)    //将数值字符串转换成数字
{                                                //识别数据类型，将数值字符串在转换成对应的数据
  switch (attr_type_) {
    case CHARS: {
      set_string(data, length);
    } break;
    case INTS: {
      num_value_.int_value_ = *(int *)data;
      length_ = length;
    } break;
    case FLOATS: {
      num_value_.float_value_ = *(float *)data;
      length_ = length;
    } break;
    case BOOLEANS: {
      num_value_.bool_value_ = *(int *)data != 0;
      length_ = length;
    } break;
     case DATES: {
      num_value_.date_value_= *(int *)data;
      length_ = length;
    } break;
    default: {
      LOG_WARN("unknown data type: %d", attr_type_);
    } break;
  }
}

void Value::set_int(int val) //int类型存值
{
  attr_type_ = INTS;
  num_value_.int_value_ = val;
  length_ = sizeof(val);
}

void Value::set_float(float val)
{
  attr_type_ = FLOATS;
  num_value_.float_value_ = val;
  length_ = sizeof(val);
}
void Value::set_boolean(bool val)
{
  attr_type_ = BOOLEANS;
  num_value_.bool_value_ = val;
  length_ = sizeof(val);
}

void Value::set_date(int val){
 
  attr_type_ = DATES;
  num_value_.date_value_ = val;
  length_ = sizeof(val);

}

void Value::set_string(const char *s, int len /*= 0*/)
{
  attr_type_ = CHARS;
  if (len > 0) {
    len = strnlen(s, len);                    //确定实际存入数字的长度
    str_value_.assign(s, len);
  } else {
    str_value_.assign(s);                     
  }
  length_ = str_value_.length();
}




void Value::set_value(const Value &value)
{
  switch (value.attr_type_) {
    case INTS: {
      set_int(value.get_int());
    } break;
    case FLOATS: {
      set_float(value.get_float());
    } break;
    case CHARS: {
      set_string(value.get_string().c_str());
    } break;
    case BOOLEANS: {
      set_boolean(value.get_boolean());
    } break;
    case DATES:{
      set_date(value.get_date());
     
    } break;
    case UNDEFINED: {
      ASSERT(false, "got an invalid value type");
    } break;
  }
}

const char *Value::data() const
{
  switch (attr_type_) {
    case CHARS: {
      return str_value_.c_str();
    } break;
    default: {
      return (const char *)&num_value_;
    } break;
  }
}

std::string Value::to_string() const
{
  std::stringstream os;
  switch (attr_type_) {
    case INTS: {
      os << num_value_.int_value_;
    } break;
    case FLOATS: {
      os << common::double_to_str(num_value_.float_value_);
    } break;
    case BOOLEANS: {
      os << num_value_.bool_value_;
    } break;
    case CHARS: {
      os << str_value_;
    } break;
    case DATES:{
      std::string strDate = "";
    //  void intDate_to_strDate_(const int intDate ,std::string &strDate){
  int year = 0;
  int month = 0;
  int day = 0;
  year = num_value_.date_value_ / 10000;
  month = (num_value_.date_value_ - year * 10000) / 100;
  day =  num_value_.date_value_ - year * 10000 - month * 100 ;
  if(month >= 10 && day >= 10){
  strDate = std::to_string(year)+"-"+std::to_string(month)+"-"+std::to_string(day);
//}

     // intDate_to_strDate_(num_value_.date_value_,strDate);//调用数据转成字符串函数，用来输出
    
      os<< strDate;
      
      }
  if(month < 10 && day >= 10){
strDate = std::to_string(year)+"-0"+std::to_string(month)+"-"+std::to_string(day);
  os<< strDate;

  }
  if(month >= 10 && day < 10){
strDate = std::to_string(year)+"-"+std::to_string(month)+"-0"+std::to_string(day);
  os<< strDate;
    
  }if(month < 10 && day < 10){
strDate = std::to_string(year)+"-0"+std::to_string(month)+"-0"+std::to_string(day);
  os<< strDate;
    
  }

    }break;
   
    default: {
      LOG_WARN("unsupported attr type: %d", attr_type_);
    } break;
  }
  return os.str();
}

int Value::compare(const Value &other) const
{
  if (this->attr_type_ == other.attr_type_) {
    switch (this->attr_type_) {
      case INTS: {
        return common::compare_int((void *)&this->num_value_.int_value_, (void *)&other.num_value_.int_value_);
      } break;
      case FLOATS: {
        return common::compare_float((void *)&this->num_value_.float_value_, (void *)&other.num_value_.float_value_);
      } break;
      case CHARS: {
        return common::compare_string((void *)this->str_value_.c_str(),
            this->str_value_.length(),
            (void *)other.str_value_.c_str(),
            other.str_value_.length());
      } break;
      case BOOLEANS: {
        return common::compare_int((void *)&this->num_value_.bool_value_, (void *)&other.num_value_.bool_value_);
      } break;
       case DATES: {
        return common::compare_date((void *)&this->num_value_.date_value_, (void *)&other.num_value_.date_value_);
      }break;
      default: {
        LOG_WARN("unsupported type: %d", this->attr_type_);
      }
    }
  } else if (this->attr_type_ == INTS && other.attr_type_ == FLOATS) {
    float this_data = this->num_value_.int_value_;
    return common::compare_float((void *)&this_data, (void *)&other.num_value_.float_value_);
  } else if (this->attr_type_ == FLOATS && other.attr_type_ == INTS) {
    float other_data = other.num_value_.int_value_;
    return common::compare_float((void *)&this->num_value_.float_value_, (void *)&other_data);
  }
  LOG_WARN("not supported");
  return -1;  // TODO return rc?
}

int Value::get_int() const 
{
  switch (attr_type_) {
    case CHARS: {
      try {
        return (int)(std::stol(str_value_));
      } catch (std::exception const &ex) {
        LOG_TRACE("failed to convert string to number. s=%s, ex=%s", str_value_.c_str(), ex.what());
        return 0;
      }
    }
    case INTS: {
      return num_value_.int_value_;
    }
    case FLOATS: {
      return (int)(num_value_.float_value_);
    }
    case BOOLEANS: {
      return (int)(num_value_.bool_value_);
    }
    default: {
      LOG_WARN("unknown data type. type=%d", attr_type_);
      return 0;
    }
  }
  return 0;
}


int Value::get_date() const{   //xiugai panduan
  switch (attr_type_)
  {
  case DATES:{
    return num_value_.date_value_;
  }
  default:{
      LOG_WARN("unknown data type. type=%d", attr_type_);
      return 0;

  }
    
  }

 return 0;


}
float Value::get_float() const
{
  switch (attr_type_) {
    case CHARS: {
      try {
        return std::stof(str_value_);
      } catch (std::exception const &ex) {
        LOG_TRACE("failed to convert string to float. s=%s, ex=%s", str_value_.c_str(), ex.what());
        return 0.0;
      }
    } break;
    case INTS: {
      return float(num_value_.int_value_);
    } break;
    case FLOATS: {
      return num_value_.float_value_;
    } break;
    case BOOLEANS: {
      return float(num_value_.bool_value_);
    } break;
    default: {
      LOG_WARN("unknown data type. type=%d", attr_type_);
      return 0;
    }
  }
  return 0;
}

std::string Value::get_string() const
{
  return this->to_string();
}

bool Value::get_boolean() const
{
  switch (attr_type_) {
    case CHARS: {
      try {
        float val = std::stof(str_value_);
        if (val >= EPSILON || val <= -EPSILON) {
          return true;
        }

        int int_val = std::stol(str_value_);
        if (int_val != 0) {
          return true;
        }

        return !str_value_.empty();
      } catch (std::exception const &ex) {
        LOG_TRACE("failed to convert string to float or integer. s=%s, ex=%s", str_value_.c_str(), ex.what());
        return !str_value_.empty();
      }
    } break;
    case INTS: {
      return num_value_.int_value_ != 0;
    } break;
    case FLOATS: {
      float val = num_value_.float_value_;
      return val >= EPSILON || val <= -EPSILON;
    } break;
    case BOOLEANS: {
      return num_value_.bool_value_;
    } break;
    default: {
      LOG_WARN("unknown data type. type=%d", attr_type_);
      return false;
    }
  }
  return false;
}
